package pers.zifeng.distributed.lock.zookeeper.event;

import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import pers.zifeng.distributed.lock.common.MysqlService;
import pers.zifeng.distributed.lock.utils.PropertiesReader;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.Properties;

/**
 * @author: zf
 * @date: 2021/05/27 10:16:07
 * @version: 1.0.0
 * @description: 使用curator中的InterProcessMutex实现分布式锁
 * 执行流程：多进程向某个容器根节点注册临时有序节点，注册成功后查看当前节点是否为首节点，是则执行业务，否则监听上一节点阻塞，等待上一节点释放再执行业务
 */
@Slf4j
public class InterProcessMutexLock {
    private static final String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];

    public void buyMaskWithLock(CuratorFramework zkClient) throws Exception {
        while (true) {
            // 创建分布式锁，根节点为/curator/locks
            InterProcessMutex mutex = new InterProcessMutex(zkClient, "/curator/locks");
            log.info("【当前线程:" + pid + "】 创建节点成功，尝试获取锁！");
            // 尝试获取锁
            mutex.acquire();
            log.info("【当前线程:" + pid + "】 获取锁成功！");
            // 抢购口罩
            if (!MysqlService.buyMask()) {
                break;
            }
            // 锁释放
            mutex.release();
            log.info("【当前线程:" + pid + "】 锁释放！");
        }
    }

    private static CuratorFramework getZkClient() throws IOException {
        Properties properties = PropertiesReader.getProperties("zookeeper.properties");
        ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);
        CuratorFramework zkClient = CuratorFrameworkFactory.builder()
                .connectString(properties.getProperty("zk.servers"))
                .sessionTimeoutMs(100000)
                .connectionTimeoutMs(10000)
                .retryPolicy(retryPolicy)
                .build();
        zkClient.start();
        return zkClient;
    }

    public static void main(String[] args) {
        try (CuratorFramework zkClient = getZkClient()) {
            InterProcessMutexLock interProcessMultiLock = new InterProcessMutexLock();
            interProcessMultiLock.buyMaskWithLock(zkClient);
        } catch (Exception e) {
            log.error("抢购口罩失败！", e);
        } finally {
            MysqlService.close();
        }
    }

}
